from flask import Blueprint, request, session, redirect, url_for, render_template, flash, current_app
from models.user import User, LoginLog, db
from utils.gm_crypto import GMCrypto
from utils.decorators import login_required
import base64
import traceback

auth_bp = Blueprint('auth', __name__, url_prefix='/auth')

def get_client_ip():
    """
    获取客户端IP地址
    """
    if request.environ.get('HTTP_X_FORWARDED_FOR') is None:
        return request.environ['REMOTE_ADDR']
    else:
        return request.environ['HTTP_X_FORWARDED_FOR']

def get_user_agent():
    """
    获取用户代理信息
    """
    return request.headers.get('User-Agent', '')[:255]  # 限制长度

def log_login_attempt(user_id, username, ip_address, user_agent, status, failure_reason=None):
    """
    记录登录尝试日志

    Args:
        user_id: 用户ID（登录失败时可以为None）
        username: 用户名
        ip_address: IP地址
        user_agent: 用户代理
        status: 登录状态 ('SUCCESS' 或 'FAILED')
        failure_reason: 失败原因（可选）
    """
    try:
        print(f"尝试记录登录日志: {username}, {ip_address}, {status}")
        login_log = LoginLog(
            user_id=user_id,
            username=username,
            ip_address=ip_address,
            user_agent=user_agent,
            status=status,
            failure_reason=failure_reason
        )
        db.session.begin_nested()  # 创建嵌套事务
        db.session.add(login_log)
        db.session.flush()  # 确保写入但不提交主事务
        print("登录日志记录成功")
    except Exception as e:
        # 日志记录失败不应该影响主要功能
        print(f"记录登录日志失败: {str(e)}")
        traceback.print_exc()
        db.session.rollback()

@auth_bp.route('/login', methods=['GET', 'POST'])
def login():
    """
    用户登录接口
    """
    if request.method == 'POST':
        # 获取客户端信息
        ip_address = get_client_ip()
        user_agent = get_user_agent()
        
        print(f"登录请求来自: {ip_address}, User-Agent: {user_agent}")
        
        # 获取用户名
        username = request.form.get('username', '')
        
        # 检查加密类型
        encryption_type = request.form.get('encryption_type', 'sm4')
        
        # 检查是否有加密密码
        encrypted_password = request.form.get('encrypted_password')
        
        if encrypted_password:
            try:
                # 初始化加密算法工具
                gm_crypto = GMCrypto()
                
                # 根据加密类型解密密码
                if encryption_type == 'aes':
                    # AES解密
                    aes_key = request.form.get('aes_key')
                    aes_iv = request.form.get('aes_iv')
                    if aes_key and aes_iv:
                        password = gm_crypto.aes_decrypt(encrypted_password, aes_key, aes_iv)
                    else:
                        password = request.form.get('password', '')
                elif encryption_type == 'sm2':
                    password = gm_crypto.sm2_decrypt(encrypted_password)
                else:
                    # 默认使用SM4解密
                    sm4_key = request.form.get('sm4_key')
                    if sm4_key:
                        password = gm_crypto.sm4_decrypt(encrypted_password, sm4_key)
                    else:
                        password = request.form.get('password', '')
            except ValueError as ve:
                # 处理解密时可能出现的常见错误
                if "private key" in str(ve).lower():
                    failure_reason = 'SM2 解密失败: 无效的私钥'
                elif "cipher text" in str(ve).lower():
                    failure_reason = 'SM2 解密失败: 无效的密文'
                else:
                    failure_reason = 'SM2 解密失败: 参数错误 - ' + str(ve)
                
                flash(failure_reason)
                print("SM2 解密错误详情:", traceback.format_exc())
                
                # 记录失败的登录尝试
                log_login_attempt(None, username, ip_address, user_agent, 'FAILED', failure_reason)
                return render_template('auth/login.html')
            except Exception as e:
                failure_reason = '密码解密失败: ' + str(e)
                flash(failure_reason)
                print("解密错误详情:", traceback.format_exc())
                
                # 记录失败的登录尝试
                log_login_attempt(None, username, ip_address, user_agent, 'FAILED', failure_reason)
                return render_template('auth/login.html')
        else:
            # 如果没有加密密码，则使用原始密码
            password = request.form.get('password', '')
        
        user = User.query.filter_by(username=username).first()
        
        if user and user.check_password(password) and user.is_active:
            session['user_id'] = user.id
            session['username'] = user.username
            
            # 记录成功的登录尝试
            log_login_attempt(user.id, username, ip_address, user_agent, 'SUCCESS')
            
            return redirect(url_for('dashboard'))
        else:
            failure_reason = '用户名或密码错误'
            flash(failure_reason)
            
            # 记录失败的登录尝试
            user_id = user.id if user else None
            log_login_attempt(user_id, username, ip_address, user_agent, 'FAILED', failure_reason)
    
    return render_template('auth/login.html')

@auth_bp.route('/register', methods=['GET', 'POST'])
def register():
    """
    用户注册接口
    """
    if request.method == 'POST':
        # 检查加密类型
        encryption_type = request.form.get('encryption_type', 'sm4')
        
        # 检查是否有加密密码
        encrypted_password = request.form.get('encrypted_password')
        
        if encrypted_password:
            try:
                # 初始化加密算法工具
                gm_crypto = GMCrypto()
                
                # 根据加密类型解密密码
                if encryption_type == 'aes':
                    # AES解密
                    aes_key = request.form.get('aes_key')
                    aes_iv = request.form.get('aes_iv')
                    if aes_key and aes_iv:
                        password = gm_crypto.aes_decrypt(encrypted_password, aes_key, aes_iv)
                    else:
                        password = request.form.get('password', '')
                elif encryption_type == 'sm2':
                    password = gm_crypto.sm2_decrypt(encrypted_password)
                else:
                    # 默认使用SM4解密
                    sm4_key = request.form.get('sm4_key')
                    if sm4_key:
                        password = gm_crypto.sm4_decrypt(encrypted_password, sm4_key)
                    else:
                        password = request.form.get('password', '')
            except ValueError as ve:
                # 处理解密时可能出现的常见错误
                if "private key" in str(ve).lower():
                    flash('SM2 解密失败: 无效的私钥')
                elif "cipher text" in str(ve).lower():
                    flash('SM2 解密失败: 无效的密文')
                else:
                    flash('SM2 解密失败: 参数错误 - ' + str(ve))
                print("SM2 解密错误详情:", traceback.format_exc())
                return render_template('auth/register.html')
            except Exception as e:
                flash('密码解密失败: ' + str(e))
                print("解密错误详情:", traceback.format_exc())
                return render_template('auth/register.html')
        else:
            # 如果没有加密密码，则使用原始密码
            password = request.form.get('password', '')
            
        username = request.form['username']
        email = request.form['email']
        
        # 检查用户是否已存在
        if User.query.filter_by(username=username).first():
            flash('用户名已存在')
            return render_template('auth/register.html')
        
        if User.query.filter_by(email=email).first():
            flash('邮箱已被注册')
            return render_template('auth/register.html')
        
        # 创建新用户
        user = User(username=username, email=email)
        user.set_password(password)
        db.session.add(user)
        db.session.commit()
        
        flash('注册成功，请登录')
        return redirect(url_for('auth.login'))
    
    return render_template('auth/register.html')

@auth_bp.route('/logout')
def logout():
    """
    用户登出接口
    """
    session.pop('user_id', None)
    session.pop('username', None)
    flash('您已成功登出')
    return redirect(url_for('auth.login'))


@auth_bp.route('/create_admin')
@login_required
def create_admin():
    """
    创建管理员用户（仅用于测试）
    """
    # 检查当前用户是否是管理员
    if not session.get('user_id') == 1:
        flash('只有管理员用户可以执行此操作')
        return redirect(url_for('auth.login'))
    
    # 检查是否已存在管理员用户
    admin_user = User.query.filter((User.id == 1) | (User.username == 'admin')).first()
    if admin_user:
        flash('管理员用户已存在')
        return redirect(url_for('auth.login'))
    
    # 创建管理员用户
    admin = User(username='admin', email='admin@example.com')
    admin.set_password('admin123')
    db.session.add(admin)
    db.session.commit()
    
    flash('管理员用户创建成功，用户名: admin, 密码: admin123')
    return redirect(url_for('auth.login'))